package com.kvest.map.mapview.engine.model;

import android.graphics.Bitmap;
import android.util.Log;
import com.kvest.map.mapview.engine.utils.Utils;

import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/**
 * Created with IntelliJ IDEA.
 * User: r.belokon
 * Date: 22.04.13
 * Time: 13:15
 * To change this template use File | Settings | File Templates.
 */
public class Tile implements DrawableItem, TextureLoadCallback{
    private static final float TILE_SIZE = 1;
    private TileInfo tileInfo;

    //Bounding of tile
    double north;
    double south;
    double east;
    double west;

    /** The texture pointer */
    private int[] textures = new int[1];

    //textureBuffer is for all tiles
    private static final FloatBuffer textureBuffer;
    static {
        float texture[] = {
                // Mapping coordinates for the vertices
                0.0f, 1.0f,		// top left		(V2)
                0.0f, 0.0f,		// bottom left	(V1)
                1.0f, 1.0f,		// top right	(V4)
                1.0f, 0.0f		// bottom right	(V3)
        };
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
        byteBuffer.order(ByteOrder.nativeOrder());
        textureBuffer = byteBuffer.asFloatBuffer();
        textureBuffer.put(texture);
        textureBuffer.position(0);
    }

    private FloatBuffer vertexBuffer;
    private int verticesCount;
    public Tile(int x, int y, int zoom) {
        tileInfo = new TileInfo(x, y, zoom);
        calcBounding(tileInfo.getX(), tileInfo.getY(), tileInfo.getZoom());

        float vertices[] = {
                TILE_SIZE * x,       -TILE_SIZE * (y + 1),  0.0f,		// V1 - bottom left
                TILE_SIZE * x,       -TILE_SIZE * y,        0.0f,		// V2 - top left
                TILE_SIZE * (x + 1), -TILE_SIZE * (y + 1),  0.0f,		// V3 - bottom right
                TILE_SIZE * (x + 1), -TILE_SIZE * y,        0.0f		// V4 - top right
        };

        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
        byteBuffer.order(ByteOrder.nativeOrder());
        vertexBuffer = byteBuffer.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        verticesCount = vertices.length / 3;

        //Load texture
        textures[0] = TileTextureManager.getInstance().loadTexture(tileInfo, this);
    }

    @Override
    public void draw(GL10 gl) {
        // bind the previously generated texture
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

        // Point to our buffers
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        // Set the face rotation
        gl.glFrontFace(GL10.GL_CW);

        // Point to our vertex buffer
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

        // Draw the vertices as triangle strip
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, verticesCount);

        //Disable the client state before leaving
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    }

    private void calcBounding(final int x, final int y, final int z) {
        north = tile2lat(y, z);
        south = tile2lat(y + 1, z);
        west = tile2lon(x, z);
        east = tile2lon(x + 1, z);
    }

    private static double tile2lon(int x, int z) {
        return x / Math.pow(2.0, z) * 360.0 - 180;
    }

    private static double tile2lat(int y, int z) {
        double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
        return Math.toDegrees(Math.atan(Math.sinh(n)));
    }

    public int getX() {
        return tileInfo.getX();
    }

    public int getY() {
        return tileInfo.getY();
    }

    public int getZoom() {
        return tileInfo.getZoom();
    }

    public void recycle() {
        TileTextureManager.getInstance().unregisterTexture(textures[0]);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Tile) {
            return tileInfo.equals(((Tile)obj).tileInfo);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return tileInfo.hashCode();
    }

    @Override
    public void textureLoaded(int textureID) {
        textures[0] = textureID;
    }
}
